package com.imooc.controller;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.google.gson.Gson;
import com.imooc.base.BaseInfoProperties;
import com.imooc.pojo.Users;
import com.imooc.result.GraceJSONResult;
import com.imooc.result.ResponseStatusEnum;
import com.imooc.service.UsersService;
import com.imooc.utils.JwtUtils;
import com.imooc.vo.SaasUserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 提供给企业端saas平台使用
 * @author liansen
 * @create 01-30-10:53
 */
@RestController
@RequestMapping("/saas")
public class SaasPassPortController extends BaseInfoProperties {

    @Autowired
    private UsersService usersService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JwtUtils jwtUtils;

    /**
     * pc端 - saas平台登录页，初始化/刷新页面(这会还没扫码)，则获得扫码登录的唯一token
     * @return
     */
    @PostMapping("/getQRToken")
    public GraceJSONResult getQRToken(){
        //生成扫码登录的token
        String qrToken = UUID.randomUUID().toString();
        //将qrToken放入redis并设置过期时间5分钟
        redisTemplate.opsForValue().set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, qrToken, 5*60, TimeUnit.SECONDS);
        //存入redis标记当前的二维码未被扫描, 设置值为0的时候表示未被扫描
        redisTemplate.opsForValue().set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "0", 5*60, TimeUnit.SECONDS);
        return GraceJSONResult.ok(qrToken);
    }


    /**
     * 手机端登录成功之后 - 用 慕聘网 - HR角色扫码, 扫码成功, 判断用户id及app的token是否ok;
     * 如果ok, 则用生成的预登录preToken覆盖上面方法的token，并存入redis,表示这个二维码已经被扫了
     * @return
     */
    @PostMapping("/scanCode")
    public GraceJSONResult scanCode(String qrToken, HttpServletRequest request){

        if(StringUtils.isBlank(qrToken)){
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);
        }
        String redisQRToken = redisTemplate.opsForValue().get(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken);
        if(StringUtils.isBlank(redisQRToken) || !qrToken.equalsIgnoreCase(redisQRToken)){
            return GraceJSONResult.errorCustom(ResponseStatusEnum.FAILED);
        }
        //获取app端用户的id以及登录token(这个登录token就是用户用手机注册登录时, 后端给前端发的jwt token)
        //前端发scanCode请求的时候, me.vue中将用户id和jwt token放进了header中,所以可以从header中获得;
        String headerUserId = request.getHeader("appUserId");
        String headerUserToken = request.getHeader("appUserToken");
        if(StringUtils.isBlank(headerUserId) || StringUtils.isBlank(headerUserToken)){
            //给手机端返回一个会话失效的提示
            return GraceJSONResult.errorCustom(ResponseStatusEnum.HR_TICKET_INVALID);
        }
        /*
            对jwt进行校验
            校验headerUserToken(也就是jwt token),判断app端用户是否登录(校验jwt);
            前端传来的jwt token是prefix@token, 所以需要切割; 校验完成得到登录用户信息;
            如果校验jwt失败,要给前端一个提示信息,之前在gateway过滤器中校验jwt的时候如果出错，
            因为gateway用不了全局异常处理,所以用的是渲染错误信息的方式给前端提示信息，
            现在可以用全局异常处理校验jwt时可能出现的异常了;
         */
        String token = headerUserToken.split(JwtUtils.at)[1];
        String userJson = jwtUtils.checkJwtToken(token);
        if(StringUtils.isBlank(userJson)){
            return GraceJSONResult.errorCustom(ResponseStatusEnum.HR_TICKET_INVALID);
        }

        //预登录token
        String preToken = UUID.randomUUID().toString();
        System.out.println("preToken: " + preToken);
        //将预登录token存入redis, 覆盖前面的 进入saas平台登录页/刷新登录页时生成的token
        redisTemplate.opsForValue().set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, preToken, 5*60, TimeUnit.SECONDS);
        //存入redis标记二维码被扫描, 设置值为1的时候表示已被扫描
        redisTemplate.opsForValue().set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "1," + preToken, 5*60, TimeUnit.SECONDS);

        //返回给手机端, 让手机端下次请求的时候携带preToken
        return GraceJSONResult.ok(preToken);
    }

    /**
     * saas平台首页每3秒定时查询qrToken是否被读取,用于页面二维码上展示是否已经被扫描的判断
     * @param qrToken
     * @return
     */
    @PostMapping("/codeHasBeenRead")
    public GraceJSONResult codeHasBeenRead(String qrToken){
        if(StringUtils.isBlank(qrToken)){
            return GraceJSONResult.error();
        }
        //获取redis中判断二维码是否被扫描的标记
        String readStr = redisTemplate.opsForValue().get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);
        if(StringUtils.isNotBlank(readStr)){
            String[] readArr = readStr.split(",");
            return GraceJSONResult.ok(readArr);
        }
        return GraceJSONResult.ok();
    }

    /**
     * 手机端点击确认登录,携带preToken到后端进行判断,如果ok则登录成功, saas端即将显示首页
     */
    @PostMapping("/goQRLogin")
    public GraceJSONResult goQRLogin(String userId, String qrToken, String preToken){
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(qrToken) || StringUtils.isBlank(preToken)){
            return GraceJSONResult.error();
        }
        String preTokenRedisArr = redisTemplate.opsForValue().get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);
        String preTokenRedis = preTokenRedisArr.split(",")[1];
        if(StringUtils.isNotBlank(preTokenRedis) && preTokenRedis.equalsIgnoreCase(preToken)){
            //根据传来的userId获取用户信息
            Users saasUser = usersService.getById(userId);
            if(saasUser == null){
                //用户不存在
                return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
            }
            String saasUserJsonString = new Gson().toJson(saasUser);
            //将临时用户信息存入redis,过期时间5分钟
            redisTemplate.opsForValue().set(REDIS_SAAS_USER_INFO + ":temp:" +  preToken, saasUserJsonString, 5*60, TimeUnit.SECONDS);
        }
        return GraceJSONResult.ok();

    }

    /**
     * saas端平台登录页面自动刷新
     * @param preToken
     * @return
     */
    @PostMapping("/checkLogin")
    public GraceJSONResult checkLogin(String preToken){
        if(StringUtils.isBlank(preToken)){
            return GraceJSONResult.error();
        }
        //获得临时用户信息
        String userJsonRedis = redisTemplate.opsForValue().get(REDIS_SAAS_USER_INFO + ":temp:" + preToken);
        if(StringUtils.isBlank(userJsonRedis)){
            return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }
        //生成jwt token, 设置过期时间为8小时, 把用户信息存进redis永不过期,并将jwt token返回给前端
        String saasUserToken = jwtUtils.createJWTWithPrefix(userJsonRedis, 8 * 60 * 60 * 1000L, TOKEN_SAAS_PREFIX);
        redisTemplate.opsForValue().set(REDIS_SAAS_USER_INFO + ":" + saasUserToken, userJsonRedis);
        return GraceJSONResult.ok(saasUserToken);
    }

    /**
     * 获取用户基本信息
     */
    @GetMapping("/info")
    public GraceJSONResult info(String token){
        //这里可以通过jwt获取用户信息, 也可以从redis中获取
//        String userJosn = jwtUtils.checkJwtToken(token);
        String userJosn = redisTemplate.opsForValue().get(REDIS_SAAS_USER_INFO + ":" + token);
        Users user = new Gson().fromJson(userJosn, Users.class);
        SaasUserVO saasUser = new SaasUserVO();
        BeanUtils.copyProperties(user, saasUser);
        return GraceJSONResult.ok(saasUser);
    }

    /**
     * 退出登录
     * @return
     */
    @PostMapping("logout")
    public GraceJSONResult logout(){
        return GraceJSONResult.ok();
    }

}